#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include  "rtp.h"


#define BUFFERSIZE 1457


struct rtpbits {
  unsigned int v:2;           /* version: 2 */
  unsigned int p:1;           /* is there padding appended: 0 */
  unsigned int x:1;           /* number of extension headers: 0 */
  unsigned int cc:4;          /* number of CSRC identifiers: 0 */
  unsigned int m:1;           /* marker: 0 */
  unsigned int pt:7;          /* payload type: 33 for MPEG2 TS - RFC 1890 */
  unsigned int sequence:16;   /* sequence number: random */
};

struct rtpheader {      /* in network byte order */
  struct rtpbits b;
  int timestamp;        /* start: random */
  int ssrc;             /* random */
};

struct sockaddr_in * serveurInitialisation (int domain, char* ipServer ,int port) ;
int createConnectedSocketTCP(char* ipServer, int port);
char** allocationTableauDeuxDimensions(char** tabMessage, int nbTab, int tailleTab);
void desAllocationTableauDeuxDimensions(char** tabMessage, int nbTab);
void envoieOption(int sock,char* buffer);
void envoieDescribe(int sock,char* buffer);
void envoieSetup(int sock,char* buffer);
void envoiePlay(int sock,char* buffer);
void envoieTearDown(int sock,char* buffer);
static int getrtp2(int fd, struct rtpheader *rh, char* data, int* lengthData, char* inputBuffer, int intputLen);


int main(int argc, char** argv)
{
	 struct hostent *hp;
	 int sock1tcp,sock2tcp,sock1udp;
	 struct sockaddr_in server; //structure serveur
	 socklen_t serverlen; //longueur de la structure sockaddr (serveur)
	 char * buffer;
	 int ret;
	 char* urlServeur = "localhost";
	 int port_serveur = 8554;
	 int port_reception_rtp = 38476;
	 int res ; // res transformation
	 char * payloadRTP ;

	 buffer = malloc(sizeof(char)*BUFFERSIZE);

	 bzero(buffer,sizeof(char)*BUFFERSIZE);

	 hp = gethostbyname(urlServeur);
	 if (hp==NULL){
		 perror("Machine distante inconnue");
		 exit(0);
	 }

	 sock1tcp = createConnectedSocketTCP(inet_ntoa( *((struct in_addr *)hp->h_addr )),port_serveur);

	 envoieOption(sock1tcp,buffer);
	 bzero(buffer,sizeof(char)*BUFFERSIZE);
	 envoieDescribe(sock1tcp,buffer);
	 bzero(buffer,sizeof(char)*BUFFERSIZE);


	 sock2tcp = createConnectedSocketTCP(inet_ntoa( *((struct in_addr *)hp->h_addr )),port_serveur);

	 envoieDescribe(sock2tcp,buffer);
	 bzero(buffer,sizeof(char)*BUFFERSIZE);
	 envoieSetup(sock2tcp,buffer);
	 bzero(buffer,sizeof(char)*BUFFERSIZE);
	 envoiePlay(sock2tcp,buffer);
	 bzero(buffer,sizeof(char)*BUFFERSIZE);
	 sock1udp = socket(AF_INET, SOCK_DGRAM, 0);
	 //Création du socket UDP pour la récéption du flux de donnée
	 serverlen = sizeof(server); //longeur de la structure server
	 bzero(&server,serverlen); //remplit la structure avec des 0
	 server.sin_family = AF_INET;
	 server.sin_addr.s_addr = INADDR_ANY;
	 server.sin_port = htons(port_reception_rtp); //port au bon encodage de donnees

	//Lien du descripteur de socket avec la structure server
	 ret = bind(sock1udp, (struct sockaddr *)&server, serverlen);
	 if (ret < 0){
		 perror("Binding impossible");
		 exit(0);
	 }

	 if(sock1udp==-1){
		  perror("Failed to create socket");
		  exit(1);
	 }

	 typedef struct {
	   unsigned int machin:1;  /* protocol version */
	 } machintruc;

	 //Reception de donnees
	 int rtplength;
	 int i = 0;

	 //POUR LE TEST
	int* longueurPayLoad;
	char* payload;
	struct rtpheader *rh ;
	rh = malloc(sizeof(struct rtpheader));
	payload = malloc(sizeof(char)*BUFFERSIZE);
	longueurPayLoad = malloc(sizeof(int));
	 bzero(buffer,sizeof(char)*BUFFERSIZE);
	 ret=-1;
	while (1){

		 //Activé le Sender Report - Goodbye
		 rtplength = recvfrom(sock1udp, buffer, BUFFERSIZE,0,  (struct sockaddr *)&server, &serverlen);

		 if(rtplength != 0) ret = getrtp2(sock1udp, rh, payload, longueurPayLoad,buffer,rtplength);
		 if(ret==0 && *longueurPayLoad == 0) break;
		 printf("%i\n",rh->b.sequence);

		 printf("%i\n",*longueurPayLoad);


		 //res = recup_paquetRTP(buffer,rtplength,payloadRTP);
		 bzero(buffer,sizeof(char)*BUFFERSIZE);
		 bzero(payload,sizeof(char)*BUFFERSIZE);

	}
	free(rh);
	free(payload);
	free(longueurPayLoad);

	 printf("Fin de la transaction");

	 //fermeture de la socket
	 close(sock1udp);

	 envoieTearDown(sock2tcp,buffer);

	exit(0);

}



struct sockaddr_in * serveurInitialisation (int domain, char* ipServer ,int port) {
    /* Initialisation du sockaddr */
	struct sockaddr_in * server;
    server = malloc(sizeof(struct sockaddr_in));       /*  */
    server->sin_family = domain;                  /* Internet/IP */
    server->sin_addr.s_addr = inet_addr(ipServer);  /* IP address */
    server->sin_port = htons(port);       /* server port */
    return server;
}

int createConnectedSocketTCP(char* ipServer, int port){
	int sock;
	struct sockaddr_in* server;

	sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sock == -1) {
	  perror("Failed to create socket");
	  exit(1);
	}
	server = serveurInitialisation(AF_INET,ipServer,port);
	/* Establish connection */
	if (connect(sock,
			server,
				sizeof(struct sockaddr_in)) != 0) {
	  perror("Failed to connect with server");
	  exit(1);
	}
	return sock;

}

char** allocationTableauDeuxDimensions(char** tabMessage, int nbTab, int tailleTab){
	int i = 0;
    //Allocation ud tableua de pointeur
    tabMessage =  malloc(sizeof(char *) * nbTab);
    if ( tabMessage  == NULL)
    {
    fprintf(stderr, "Erreur, impossible d'allouer la mémoire");
    exit (-1);
    }
    //Allocation de chacun des tableaux
    for(i=0;i<nbTab;i++)
    {
    	tabMessage[i] = (char *) malloc(sizeof(char) * tailleTab);
    }
    return tabMessage;
}

void desAllocationTableauDeuxDimensions(char** tabMessage, int nbTab){
	int i = 0;
	for(i=0;i<nbTab;i++)free(tabMessage[i]);
    free(tabMessage);

}

void envoieOption(int sock,char* buffer){
	int i;
	char** tabMessage;
	tabMessage = allocationTableauDeuxDimensions(tabMessage,10,100);

	strcpy(tabMessage[0],"OPTIONS rtsp://127.0.0.1:8554 RTSP/1.0\r\n");
	strcpy(tabMessage[1],"CSeq: 1\r\n");
	strcpy(tabMessage[2],"User-Agent: RealMedia Player Version 6.0.9.1235 (linux-2.0-libc6-i386-gcc2.95)\r\n");
	strcpy(tabMessage[3],"ClientChallenge: 9e26d33f2984236010ef6253fb1887f7\r\n");
	strcpy(tabMessage[4],"PlayerStarttime: [28/03/2003:22:50:23 00:00]\r\n");
	strcpy(tabMessage[5],"CompanyID: KnKV4M4I/B2FjJ1TToLycw==\r\n");
	strcpy(tabMessage[6],"GUID: 00000000-0000-0000-0000-000000000000\r\n");
	strcpy(tabMessage[7],"RegionData: 0\r\n");
	strcpy(tabMessage[8],"ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586\r\n");
	strcpy(tabMessage[9],"\r\n");

	/* Send the word to the server */
	for(i=0;i<10;i++){
		if (send(sock, tabMessage[i], strlen(tabMessage[i]), 0) == -1) {
			perror("Mismatch in number of sent bytes");
			exit(1);
		}
	}
	desAllocationTableauDeuxDimensions(tabMessage,10);

	if (recv(sock,buffer,BUFFERSIZE-1,0) == -1) {
		perror("BUG");
		exit(-1);
	}
	//printf("%s",buffer);
}


void envoieDescribe(int sock,char* buffer){
	int i;
		char** tabMessage=NULL;
		tabMessage = allocationTableauDeuxDimensions(tabMessage,4,100);

	//Envoie deuxieme requete
		strcpy(tabMessage[0],"DESCRIBE rtsp://127.0.0.1:8554/video_1.264 RTSP/1.0\r\n");
		strcpy(tabMessage[1],"CSeq: 2\r\n");
		strcpy(tabMessage[2],"Accept: application/sdp\r\n");
		strcpy(tabMessage[3],"\r\n");


		/* Send the word to the server */
		for(i=0;i<4;i++){
			if (send(sock, tabMessage[i], strlen(tabMessage[i]), 0) == -1) {
				perror("Mismatch in number of sent bytes");
				exit(1);
			}
		}
		if (recv(sock,buffer,BUFFERSIZE-1,0) == -1) {
			perror("BUG");
			exit(-1);
		}
		desAllocationTableauDeuxDimensions(tabMessage,4);


}


void envoieSetup(int sock,char* buffer){
	int i;
	char** tabMessage=NULL;
	tabMessage = allocationTableauDeuxDimensions(tabMessage,5,100);

	strcpy(tabMessage[0],"SETUP rtsp://127.0.0.1:8554/video_1.264/track1 RTSP/1.0\r\n");
	strcpy(tabMessage[1],"CSeq: 3\r\n");
	strcpy(tabMessage[2],"User-Agent: MPlayer (LIVE555 Streaming Media v2011.01.24)\r\n");
	strcpy(tabMessage[3],"Transport: RTP/AVP;unicast;client_port=38476-38477\r\n");
	strcpy(tabMessage[4],"\r\n");

	/* Send the word to the server */
	for(i=0;i<5;i++){
		if (send(sock, tabMessage[i], strlen(tabMessage[i]), 0) == -1) {
			perror("Mismatch in number of sent bytes");
			exit(1);
		}
	}
	desAllocationTableauDeuxDimensions(tabMessage,5);

	if (recv(sock,buffer,BUFFERSIZE-1,0) == -1) {
		perror("BUG");
		exit(-1);
	}

}


void envoiePlay(int sock,char* buffer){
	int i;
	char** tabMessage=NULL;
	tabMessage = allocationTableauDeuxDimensions(tabMessage,6,100);

	strcpy(tabMessage[0],"PLAY rtsp://127.0.0.1:8554/video_1.264/ RTSP/1.0\r\n");
	strcpy(tabMessage[1],"CSeq: 4\r\n");
	strcpy(tabMessage[2],"User-Agent: MPlayer (LIVE555 Streaming Media v2011.01.24)\r\n");
	strcpy(tabMessage[3],"Session: 4DDF3F9A\r\n");
	strcpy(tabMessage[4],"Range: npt=0.000-\r\n");
	strcpy(tabMessage[5],"\r\n");

	/* Send the word to the server */
	for(i=0;i<6;i++){
		if (send(sock, tabMessage[i], strlen(tabMessage[i]), 0) == -1) {
			perror("Mismatch in number of sent bytes");
			exit(1);
		}
	}
	desAllocationTableauDeuxDimensions(tabMessage,6);

	if (recv(sock,buffer,BUFFERSIZE-1,0) == -1) {
		perror("BUG");
		exit(-1);
	}

}

void envoieTearDown(int sock,char* buffer){
	int i;
	char** tabMessage=NULL;
	tabMessage = allocationTableauDeuxDimensions(tabMessage,5,100);
	strcpy(tabMessage[0],"TEARDOWN rtsp://148.60.11.242:8554/video_1.264/ RTSP/1.0\r\n");
	strcpy(tabMessage[1],"CSeq: 5\r\n");
	strcpy(tabMessage[2],"User-Agent: MPlayer (LIVE555 Streaming Media v2011.01.24)\r\n");
	strcpy(tabMessage[3],"Session: 4DDF3F9A\r\n");
	strcpy(tabMessage[4],"\r\n");

	/* Send the word to the server */
	for(i=0;i<5;i++){
		if (send(sock, tabMessage[i], strlen(tabMessage[i]), 0) == -1) {
			perror("Mismatch in number of sent bytes");
			exit(1);
		}
	}
	desAllocationTableauDeuxDimensions(tabMessage,5);

	if (recv(sock,buffer,BUFFERSIZE-1,0) == -1) {
		perror("BUG");
		exit(-1);
	}
}

static int getrtp2(int fd, struct rtpheader *rh, char* data, int* lengthData, char * inputBuffer, int intputLen) {
  unsigned int intP;
  char* charP = (char*) &intP;
  int headerSize;
  int lengthPacket;
  lengthPacket=intputLen;

  if (lengthPacket<0){
    printf("rtp: socket read error\n");
    exit(-1);
    }
  else if (lengthPacket<12){
    printf("rtp: packet too small (%d) to be an rtp frame (>12bytes)\n", lengthPacket);
    exit(-1);
    }
  if(lengthPacket<12) {
    *lengthData = 0;
    return 0;
  }

  rh->b.v  = (unsigned int) ((inputBuffer[0]>>6)&0x03);
  rh->b.p  = (unsigned int) ((inputBuffer[0]>>5)&0x01);
  rh->b.x  = (unsigned int) ((inputBuffer[0]>>4)&0x01);
  rh->b.cc = (unsigned int) ((inputBuffer[0]>>0)&0x0f);
  rh->b.m  = (unsigned int) ((inputBuffer[1]>>7)&0x01);
  rh->b.pt = (unsigned int) ((inputBuffer[1]>>0)&0x7f);
  intP = 0;
  memcpy(charP+2,&inputBuffer[2],2);
  rh->b.sequence = ntohl(intP);
  intP = 0;
  memcpy(charP,&inputBuffer[4],4);
  rh->timestamp = ntohl(intP);

  headerSize = 12 + 4*rh->b.cc; /* in bytes */

  *lengthData = lengthPacket - headerSize;
  data = (char*) inputBuffer + headerSize;

  //  mp_msg(MSGT_NETWORK,MSGL_DBG2,"Reading rtp: v=%x p=%x x=%x cc=%x m=%x pt=%x seq=%x ts=%x lgth=%d\n",rh->b.v,rh->b.p,rh->b.x,rh->b.cc,rh->b.m,rh->b.pt,rh->b.sequence,rh->timestamp,lengthPacket);^M

  return 0;
}





